/**
 * 文件上传管理通用逻辑 Hook
 *
 * 抽取文件上传的通用业务逻辑
 * 包括文件选择、上传、进度、预览等功能
 */

import { ref, computed, type Ref } from "vue";
import type {
  UploadFile,
  UploadFiles,
  UploadProgressEvent,
  UploadRawFile,
} from "element-plus";

/**
 * 文件上传配置接口
 */
interface UseUploadOptions {
  /** 上传API地址 */
  action?: string;
  /** 允许的文件类型 */
  accept?: string;
  /** 文件大小限制(MB) */
  maxSize?: number;
  /** 最大文件数量 */
  maxCount?: number;
  /** 是否支持多选 */
  multiple?: boolean;
  /** 是否自动上传 */
  autoUpload?: boolean;
  /** 上传请求头 */
  headers?: Record<string, string>;
  /** 上传额外参数 */
  data?: Record<string, any>;
  /** 文件参数名 */
  name?: string;
  /** 是否显示文件列表 */
  showFileList?: boolean;
  /** 是否支持拖拽上传 */
  drag?: boolean;
  /** 上传前钩子 */
  beforeUpload?: (file: UploadRawFile) => boolean | Promise<boolean>;
  /** 上传成功回调 */
  onSuccess?: (response: any, file: UploadFile, fileList: UploadFiles) => void;
  /** 上传失败回调 */
  onError?: (error: Error, file: UploadFile, fileList: UploadFiles) => void;
}

/**
 * 文件上传Hook返回值
 */
interface UseUploadReturn {
  // 状态
  fileList: Ref<UploadFile[]>;
  uploading: Ref<boolean>;
  uploadProgress: Ref<number>;

  // 计算属性
  canUpload: Ref<boolean>;
  hasFiles: Ref<boolean>;
  uploadedFiles: Ref<UploadFile[]>;
  failedFiles: Ref<UploadFile[]>;

  // 方法
  selectFiles: () => void;
  uploadFiles: (files?: File[]) => Promise<any[]>;
  removeFile: (file: UploadFile | number) => void;
  clearFiles: () => void;
  retryUpload: (file?: UploadFile) => Promise<any>;
  previewFile: (file: UploadFile) => void;
  downloadFile: (file: UploadFile) => void;
  validateFile: (file: File) => { valid: boolean; message?: string };
  getFileUrl: (file: UploadFile) => string;
  getFileSize: (size: number) => string;
  getFileType: (file: UploadFile) => string;
}

/**
 * 文件上传管理通用Hook
 */
export function useUpload(options: UseUploadOptions = {}): UseUploadReturn {
  const {
    action = "/api/upload",
    accept = "*",
    maxSize = 10, // 10MB
    maxCount = 5,
    multiple = true,
    autoUpload = true,
    headers = {},
    data = {},
    name = "file",
    showFileList = true,
    drag = false,
    beforeUpload,
    onSuccess,
    onError,
  } = options;

  // 状态
  const fileList = ref<UploadFile[]>([]);
  const uploading = ref(false);
  const uploadProgress = ref(0);

  // 计算属性
  const canUpload = computed(() => {
    return !uploading.value && fileList.value.length < maxCount;
  });

  const hasFiles = computed(() => {
    return fileList.value.length > 0;
  });

  const uploadedFiles = computed(() => {
    return fileList.value.filter((file) => file.status === "success");
  });

  const failedFiles = computed(() => {
    return fileList.value.filter((file) => file.status === "fail");
  });

  /**
   * 验证文件
   */
  const validateFile = (file: File): { valid: boolean; message?: string } => {
    // 检查文件类型
    if (accept !== "*") {
      const acceptTypes = accept.split(",").map((type) => type.trim());
      const fileType = file.type;
      const fileName = file.name.toLowerCase();

      const isValidType = acceptTypes.some((type) => {
        if (type.startsWith(".")) {
          return fileName.endsWith(type);
        }
        return fileType.includes(type.replace("*", ""));
      });

      if (!isValidType) {
        return {
          valid: false,
          message: `不支持的文件类型，只支持: ${accept}`,
        };
      }
    }

    // 检查文件大小
    const fileSizeMB = file.size / 1024 / 1024;
    if (fileSizeMB > maxSize) {
      return {
        valid: false,
        message: `文件大小不能超过 ${maxSize}MB`,
      };
    }

    // 检查文件数量
    if (fileList.value.length >= maxCount) {
      return {
        valid: false,
        message: `最多只能上传 ${maxCount} 个文件`,
      };
    }

    return { valid: true };
  };

  /**
   * 选择文件
   */
  const selectFiles = (): void => {
    const input = document.createElement("input");
    input.type = "file";
    input.accept = accept;
    input.multiple = multiple;

    input.onchange = (event) => {
      const files = (event.target as HTMLInputElement).files;
      if (files) {
        const fileArray = Array.from(files);
        if (autoUpload) {
          uploadFiles(fileArray);
        } else {
          // 添加到文件列表但不上传
          fileArray.forEach((file, index) => {
            const uploadFile: UploadFile = {
              name: file.name,
              size: file.size,
              status: "ready",
              uid: Date.now() + index,
              raw: file,
            };
            fileList.value.push(uploadFile);
          });
        }
      }
    };

    input.click();
  };

  /**
   * 上传文件
   */
  const uploadFiles = async (files?: File[]): Promise<any[]> => {
    const filesToUpload =
      files ||
      fileList.value
        .filter((f) => f.status === "ready" || f.status === "fail")
        .map((f) => f.raw!)
        .filter(Boolean);

    if (filesToUpload.length === 0) {
      return [];
    }

    const results: any[] = [];
    uploading.value = true;
    uploadProgress.value = 0;

    try {
      for (let i = 0; i < filesToUpload.length; i++) {
        const file = filesToUpload[i];

        // 验证文件
        const validation = validateFile(file);
        if (!validation.valid) {
          ElMessage.error(validation.message!);
          continue;
        }

        // 执行前置钩子
        if (beforeUpload) {
          const canUpload = await beforeUpload(file as UploadRawFile);
          if (!canUpload) continue;
        }

        // 查找或创建文件项
        let fileItem = fileList.value.find((f) => f.raw === file);
        if (!fileItem) {
          fileItem = {
            name: file.name,
            size: file.size,
            status: "uploading",
            uid: Date.now() + i,
            raw: file,
          };
          fileList.value.push(fileItem);
        } else {
          fileItem.status = "uploading";
        }

        try {
          const result = await uploadSingleFile(file, fileItem);
          results.push(result);

          fileItem.status = "success";
          fileItem.response = result;

          if (onSuccess) {
            onSuccess(result, fileItem, fileList.value);
          }
        } catch (error) {
          fileItem.status = "fail";

          if (onError) {
            onError(error as Error, fileItem, fileList.value);
          }
        }

        // 更新进度
        uploadProgress.value = Math.round(
          ((i + 1) / filesToUpload.length) * 100,
        );
      }
    } finally {
      uploading.value = false;
      uploadProgress.value = 0;
    }

    return results;
  };

  /**
   * 上传单个文件
   */
  const uploadSingleFile = async (
    file: File,
    fileItem: UploadFile,
  ): Promise<any> => {
    const formData = new FormData();
    formData.append(name, file);

    // 🧹 安全添加额外参数，防止null值转换为"null"字符串
    Object.keys(data).forEach((key) => {
      const value = data[key];
      // 过滤null、undefined和"null"字符串
      if (value !== null && 
          value !== undefined && 
          value !== "" && 
          value !== "null" &&
          String(value) !== "null") {
        formData.append(key, String(value));
        console.log(`[useUpload] 📤 添加上传参数: ${key} = ${value}`);
      } else {
        console.warn(`[useUpload] ⚠️ 跳过无效上传参数: ${key} = ${value} (${typeof value})`);
      }
    });

    const response = await fetch(action, {
      method: "POST",
      headers: {
        ...headers,
      },
      body: formData,
    });

    if (!response.ok) {
      throw new Error(`上传失败: ${response.statusText}`);
    }

    return await response.json();
  };

  /**
   * 移除文件
   */
  const removeFile = (file: UploadFile | number): void => {
    const index =
      typeof file === "number"
        ? file
        : fileList.value.findIndex((f) => f.uid === file.uid);

    if (index > -1) {
      fileList.value.splice(index, 1);
    }
  };

  /**
   * 清空文件列表
   */
  const clearFiles = (): void => {
    fileList.value = [];
  };

  /**
   * 重新上传失败的文件
   */
  const retryUpload = async (file?: UploadFile): Promise<any> => {
    if (file) {
      file.status = "ready";
      return await uploadFiles([file.raw!]);
    } else {
      // 重新上传所有失败的文件
      const failedFiles = fileList.value.filter((f) => f.status === "fail");
      failedFiles.forEach((f) => (f.status = "ready"));
      return await uploadFiles();
    }
  };

  /**
   * 预览文件
   */
  const previewFile = (file: UploadFile): void => {
    if (file.raw && file.raw.type.startsWith("image/")) {
      // 图片预览
      const url = URL.createObjectURL(file.raw);
      window.open(url, "_blank");
    } else if (file.url) {
      // 其他文件类型通过URL预览
      window.open(file.url, "_blank");
    }
  };

  /**
   * 下载文件
   */
  const downloadFile = (file: UploadFile): void => {
    if (file.url) {
      const link = document.createElement("a");
      link.href = file.url;
      link.download = file.name;
      link.click();
    }
  };

  /**
   * 获取文件URL
   */
  const getFileUrl = (file: UploadFile): string => {
    if (file.url) return file.url;
    if (file.raw) return URL.createObjectURL(file.raw);
    return "";
  };

  /**
   * 格式化文件大小
   */
  const getFileSize = (size: number): string => {
    if (size < 1024) return size + " B";
    if (size < 1024 * 1024) return (size / 1024).toFixed(1) + " KB";
    if (size < 1024 * 1024 * 1024)
      return (size / 1024 / 1024).toFixed(1) + " MB";
    return (size / 1024 / 1024 / 1024).toFixed(1) + " GB";
  };

  /**
   * 获取文件类型
   */
  const getFileType = (file: UploadFile): string => {
    const extension = file.name.split(".").pop()?.toLowerCase() || "";

    const imageTypes = ["jpg", "jpeg", "png", "gif", "bmp", "webp"];
    const documentTypes = [
      "doc",
      "docx",
      "pdf",
      "txt",
      "xls",
      "xlsx",
      "ppt",
      "pptx",
    ];
    const videoTypes = ["mp4", "avi", "mov", "wmv", "flv", "mkv"];
    const audioTypes = ["mp3", "wav", "flac", "aac", "ogg"];

    if (imageTypes.includes(extension)) return "image";
    if (documentTypes.includes(extension)) return "document";
    if (videoTypes.includes(extension)) return "video";
    if (audioTypes.includes(extension)) return "audio";

    return "file";
  };

  return {
    // 状态
    fileList,
    uploading,
    uploadProgress,

    // 计算属性
    canUpload,
    hasFiles,
    uploadedFiles,
    failedFiles,

    // 方法
    selectFiles,
    uploadFiles,
    removeFile,
    clearFiles,
    retryUpload,
    previewFile,
    downloadFile,
    validateFile,
    getFileUrl,
    getFileSize,
    getFileType,
  };
}

/**
 * 图片上传Hook
 */
export function useImageUpload(options: Partial<UseUploadOptions> = {}) {
  return useUpload({
    accept: "image/*",
    maxSize: 5, // 5MB
    maxCount: 10,
    ...options,
  });
}

/**
 * 文档上传Hook
 */
export function useDocumentUpload(options: Partial<UseUploadOptions> = {}) {
  return useUpload({
    accept: ".doc,.docx,.pdf,.txt,.xls,.xlsx,.ppt,.pptx",
    maxSize: 20, // 20MB
    maxCount: 5,
    ...options,
  });
}

/**
 * Excel导入Hook
 */
export function useExcelImport(options: Partial<UseUploadOptions> = {}) {
  return useUpload({
    accept: ".xls,.xlsx",
    maxSize: 10, // 10MB
    maxCount: 1,
    autoUpload: false,
    ...options,
  });
}
